#include "usart.h"
#include <string.h>


#define USART0_RDATA_ADDRESS      (&USART_RDATA(USART0))
#define USART0_TDATA_ADDRESS      (&USART_TDATA(USART0))

#define USART1_RDATA_ADDRESS      (&USART_RDATA(USART1))
#define USART1_TDATA_ADDRESS      (&USART_TDATA(USART1))

Com Com0={.Tx_Idle=true},Com1={.Tx_Idle=true};

static void usart0_config(uint32_t baudrate)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USART TX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);

    /* connect port to USART RX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);

    /* configure USART TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);

    /* configure USART RX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /* configure RS485 DE pin as push-pull*/
    gpio_mode_set(GPIOA,GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,GPIO_PIN_11);
    gpio_output_options_set(GPIOA,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_11);

    /* USART configure */
    usart_deinit(USART0);
    usart_baudrate_set(USART0, baudrate);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);

    usart_enable(USART0);
}

static void usart0_dma_init(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* initialize DMA channel 0 */
    dma_deinit(DMA_CH0);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART0_TX;
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr  = (uint32_t)Com0.Tx_Buf;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = ARRAYNUM(Com0.Tx_Buf);
    dma_init_struct.periph_addr  = (uint32_t)USART0_TDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH0, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH0);
    dma_memory_to_memory_disable(DMA_CH0);
    /* disable the DMAMUX_MUXCH0 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH0);
    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
    /* enable DMA channel 0 transfer complete interrupt */
    dma_interrupt_enable(DMA_CH0, DMA_INT_FTF);
    /* enable DMA channel 0 */
    // dma_channel_enable(DMA_CH0);


    /* initialize DMA channel 1 */
    dma_deinit(DMA_CH1);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART0_RX;
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr  = (uint32_t)Com0.Rx_Buf;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = ARRAYNUM(Com0.Rx_Buf);
    dma_init_struct.periph_addr  = (uint32_t)USART0_RDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH1, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH1);
    dma_memory_to_memory_disable(DMA_CH1);
    /* disable the DMAMUX_MUXCH1 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH1);
    /* USART DMA enable for reception */
    usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
    /* enable DMA channel 1 transfer complete interrupt */
    // dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);
    usart_interrupt_enable(USART0,USART_INT_IDLE);
    /* enable DMA channel 1 */
    dma_channel_enable(DMA_CH1);
}

void set_rs485_direction(COM_DIRECTION_t DIRECTION)
{
    if(RX == DIRECTION)
    {
        gpio_bit_write(GPIOA, GPIO_PIN_11, RESET);
    }
    else
    {
        gpio_bit_write(GPIOA, GPIO_PIN_11, SET);
    }
}

static void usart0_nvic_config(void)
{
    //串口空闲接收中断使能
    nvic_irq_enable(USART0_IRQn, 0);
    //DMA发送完成中断使能
    nvic_irq_enable(DMA_Channel0_IRQn, 0);
}

static void debug_usart_init(uint32_t baudrate)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);

    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);

    /* connect port to USART TX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);

    /* connect port to USART RX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);

    /* configure USART TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

    /* configure USART RX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);

    /* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, baudrate);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);

    usart_enable(USART1);
}

static void debug_usart_dma_config(void)
{
    dma_parameter_struct dma_init_struct;
    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* initialize DMA channel 2 */
    dma_deinit(DMA_CH2);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART1_TX;
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr  = (uint32_t)Com1.Tx_Buf;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
//    dma_init_struct.number       = ARRAYNUM(Com1.Tx_Buf);
	dma_init_struct.number       = 0;
    dma_init_struct.periph_addr  = (uint32_t)USART1_TDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH2, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH2);
    dma_memory_to_memory_disable(DMA_CH2);
    /* disable the DMAMUX_MUXCH0 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH2);
    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
    /* enable DMA channel 0 transfer complete interrupt */
    // dma_interrupt_enable(DMA_CH2, DMA_INT_FTF);
    /* enable DMA channel 0 */
    dma_channel_enable(DMA_CH2);

    /* initialize DMA channel 3 */
    dma_deinit(DMA_CH3);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART1_RX;
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr  = (uint32_t)Com1.Rx_Buf;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = ARRAYNUM(Com1.Rx_Buf);
    dma_init_struct.periph_addr  = (uint32_t)USART1_RDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH3, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH3);
    dma_memory_to_memory_disable(DMA_CH3);
    /* disable the DMAMUX_MUXCH1 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH3);
    /* USART DMA enable for reception */
    usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
    /* enable DMA channel 1 transfer complete interrupt */
    // dma_interrupt_enable(DMA_CH3, DMA_INT_FTF);
    /* enable DMA channel 1 */
    dma_channel_enable(DMA_CH3);
}

void usart_config(void)
{
		#if 1
    //RS485初始化配置
    usart0_config(19200);
    usart0_nvic_config();
    usart0_dma_init();

    set_rs485_direction(RX);
		#endif

    //debug串口初始化配置
    debug_usart_init(115200);
    debug_usart_dma_config();
}



/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(USART1, (uint8_t)ch);
    while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
    return ch;
}

void usart0_tx(uint8_t *buf, uint32_t len)
{
    if(Com0.Tx_Idle == true)
    {
        dma_memory_address_config(DMA_CH0,(uint32_t)buf);
        dma_transfer_number_config(DMA_CH0,len);
        Com0.Tx_Idle = false;
        set_rs485_direction(TX);
        dma_interrupt_enable(DMA_CH0,DMA_INT_FTF);
        dma_channel_enable(DMA_CH0);
    }
}

bool get_usart0_rx_flag(void)
{
    return Com0.Rx_Complete;
}

void clear_rx_flag(void)
{
    Com0.Rx_Complete = false;
}

void clear_usart0_rx_buf(void)
{
    memset((void*)&Com0.Rx_Buf,0,sizeof(Com0.Rx_Buf));
    // clear_rx_flag();
}

/*!
    \brief      this function handles DMA_Channel0_IRQHandler interrupt
    \param[in]  none
    \param[out] none
    \retval     none
*/
void DMA_Channel0_IRQHandler(void)
{
    if(RESET != dma_interrupt_flag_get(DMA_CH0, DMA_INT_FLAG_FTF))
    {
        dma_interrupt_flag_clear(DMA_CH0, DMA_INT_FLAG_G);

        dma_interrupt_disable(DMA_CH0, DMA_INT_FTF);
        dma_channel_disable(DMA_CH0);
        Com0.Tx_Idle = true;
        Com0.Tx_Complete = true;
    }
}

/*!
    \brief      this function handles USART interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void USART0_IRQHandler(void)
{
    if(RESET != usart_interrupt_flag_get(USART0,USART_INT_FLAG_IDLE))
    {
        dma_channel_disable(DMA_CH1);
        // usart_interrupt_disable(USART0,USART_INT_IDLE);
//        usart_data_receive(USART0);
        usart_interrupt_flag_clear(USART0,USART_INT_FLAG_IDLE);

        Com0.Frame_Len = ARRAYNUM(Com0.Rx_Buf)- dma_transfer_number_get(DMA_CH1);
        if((Com0.Frame_Len < ARRAYNUM(Com0.Rx_Buf)) && (Com0.Frame_Len > 0))
        {
            Com0.Rx_Complete = true;
            
			// usart_dma_receive_config(USART0, USART_RECEIVE_DMA_DISABLE);
        }
        else
        {
            memset(Com0.Rx_Buf,0,ARRAYNUM(Com0.Rx_Buf));
            // usart_interrupt_enable(USART0,USART_INT_IDLE);

        }
        
        dma_transfer_number_config(DMA_CH1,ARRAYNUM(Com0.Rx_Buf));
        dma_channel_enable(DMA_CH1);

        // nvic_irq_disable(USART0_IRQn);
    } 
}


